﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Threading;
using System.IO;
using GMusicBox.Core;
using System.Xml;

namespace GMusicBox
{
    public partial class frmDownloader : Form
    {
        public frmDownloader()
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            dwr.DownloadCompleted += new EventHandler(dwr_DownloadCompleted);
            dwr.Connected += new EventHandler(dwr_Connected);
            dwr.ConnectFailed += new EventHandler(dwr_ConnectFailed);

            if (File.Exists(Settings.SettingSavePath + "\\Config\\Downloads.xml"))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(Settings.SettingSavePath + "\\Config\\Downloads.xml");
                XmlNodeList xnl = xd.SelectSingleNode("Downloads").SelectNodes("download");

                for (int i = 0; i < xnl.Count; i++)
                {
                    DownloadTask dt = new DownloadTask(Song.Create(xnl[i].SelectSingleNode("id").InnerText));
                    dt.FileName = xnl[i].SelectSingleNode("saveto").InnerText;
                    if (Path.GetExtension(dt.FileName).ToLower() == ".lrc")
                        dt.IsLyrics = true;

                    dt.IsCompleted = Convert.ToBoolean(xnl[i].SelectSingleNode("iscomplete").InnerText);

                    XmlNode isLyrics = xnl[i].SelectSingleNode("isLyrics");
                    if (isLyrics != null) dt.IsLyrics = Convert.ToBoolean(isLyrics.InnerText);

                    this.dt.Add(dt);
                }
            }

            btnDelete.Text = "删除";
            btnOpen.Text = "打开";
            btnOpenFolder.Text = "打开文件夹";
            btnReStart.Text = "重新下载";
            btnStartPause.Text = "开始/暂停";

            this.TopMost = Core.Setting.StandardSetting.TopMost;

            AddRow();
            RefreshTask();
        }

        public Downloader dwr = new Downloader();
        public List<DownloadTask> dt = new List<DownloadTask>();
        long oldDownloadedSize = 0;
        delegate void SetTimerEnableCallBack();

        private void dwr_DownloadCompleted(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            for (int i = 0; i < dt.Count; i++)
            {
                if (dt[i].IsDownloading && dgw.Rows[i].Cells[5].Value.ToString() != "错误")
                {
                    dt[i].IsDownloading = false;
                    dt[i].IsCompleted = true;
                    SetState(i, 4);

                    dgw.Rows[i].Cells[3].Value = PaintProgressBar(1, dgw.Columns[3].Width);
                    dgw.Rows[i].Cells[4].Value = "0 KB/s";
                    dgw.Rows[i].Cells[5].Value = "已完成";
                    oldDownloadedSize = 0;
                    break;
                }
            }
            RefreshTask();
            SaveAllTasks();
        }

        private void dwr_Connected(object sender, EventArgs e)
        {
            try
            {
                dgw.Rows[GetDownloadingIndex()].Cells[2].Value = Helper.GetStringFromBytes(dwr.FileLenght);
                timer1.Enabled = true;
            }
            catch { }
        }

        private void dwr_ConnectFailed(object sender, EventArgs e)
        {
            int i = GetDownloadingIndex();
            if (i == -1) return;
            dgw.Rows[i].Cells[3].Value = PaintProgressBar(-1, dgw.Columns[3].Width);
            dgw.Rows[i].Cells[4].Value = "0 KB/s";
            dgw.Rows[i].Cells[5].Value = "错误";
            SetState(i, 3);
            oldDownloadedSize = 0;

            timer1.Enabled = false;
            dt[i].IsDownloading = false;
            dt[i].IsCompleted = true;
            dwr.IsDownloadStarted = false;

            RefreshTask();
            SaveAllTasks();
        }

        private Bitmap PaintProgressBar(double percentage, int width)
        {
            Bitmap b = new Bitmap(width - 15, 15);
            Graphics g = Graphics.FromImage(b);
            int w = (int)((width - 15) * (double.IsInfinity(percentage) || double.IsNaN(percentage) || percentage >= 0 ? percentage : 1));
            g.SmoothingMode = SmoothingMode.AntiAlias;

            if (percentage < 0)
                g.FillRectangle(new LinearGradientBrush(new Rectangle(0, 0, w, 14), Color.FromArgb(255, 0, 0), Color.FromArgb(202, 78, 52), LinearGradientMode.Vertical), new Rectangle(0, 0, w, 14));
            else if (percentage >= 1)
                g.FillRectangle(new LinearGradientBrush(new Rectangle(0, 0, w, 14), Color.FromArgb(156, 216, 154), Color.FromArgb(110, 180, 87), LinearGradientMode.Vertical), new Rectangle(0, 0, w, 14));
            else if (percentage != 0 && w != 0)
                g.FillRectangle(new LinearGradientBrush(new Rectangle(0, 0, w, 14), Color.FromArgb(180, 210, 241), Color.FromArgb(102, 148, 227), LinearGradientMode.Vertical), new Rectangle(0, 0, w, 14));
            g.DrawPath(Pens.Black, Helper.CreateRoundedRectangle(new Rectangle(0, 0, b.Width - 1, 14), 3));

            if (double.IsInfinity(percentage) || double.IsNaN(percentage)) percentage = 0;
            if (percentage < 0) percentage = 1;
            string s = Math.Round(percentage * 100, 2).ToString() + "%";
            SizeF sf = g.MeasureString(s, this.Font);
            g.DrawString(s, new Font("宋体", 9), Brushes.Black, new PointF(b.Width / 2 - (int)sf.Width / 2, b.Height / 2 - (int)sf.Height / 2));

            g.Dispose();
            return b;
        }

        private int GetDownloadingIndex()
        {
            for (int i = 0; i < dt.Count; i++)
                if (dt[i].IsDownloading)
                    return i;
            return -1;
        }

        public void AddRow()
        {
            for (int i = dgw.Rows.Count; i < dt.Count; i++)
            {
                int state = 1;
                if (dt[i].IsCompleted)
                    if (File.Exists(dt[i].FileName)) state = 4;
                    else state = 3;

                DataGridViewRow d = new DataGridViewRow();
                d.Cells.Add(new DataGridViewImageCell());
                d.Cells.Add(new DataGridViewTextBoxCell { Value = Path.GetFileName(dt[i].FileName) });
                d.Cells.Add(new DataGridViewTextBoxCell { Value = state == 3 ? "文件不存在" : (dt[i].IsCompleted ? Helper.GetStringFromBytes(new FileInfo(dt[i].FileName).Length) : "未知") });
                d.Cells.Add(new DataGridViewImageCell { Value = PaintProgressBar(state == 3 ? -1 : (dt[i].IsCompleted ? 1 : 0), dgw.Columns[3].Width) });
                d.Cells.Add(new DataGridViewTextBoxCell { Value = "0 KB/s" });
                d.Cells.Add(new DataGridViewTextBoxCell { Value = dt[i].IsCompleted ? "已完成" : "00:00:00" });
                dgw.Rows.Add(d);
                SetState(i, state);
            }

            SaveAllTasks();
        }

        public void RefreshTask()
        {
            int i = 0, firstNotCompleted = -1;
            for (i = 0; i < dt.Count; i++)
            {
                if (firstNotCompleted == -1 && !dt[i].IsCompleted)
                    firstNotCompleted = i;
                if (dt[i].IsDownloading) break;
            }

            if (i == dt.Count && dt.Count != 0 && firstNotCompleted != -1)
            {
                oldDownloadedSize = 0;
                SetState(firstNotCompleted, 2);
                Thread t = new Thread(new ParameterizedThreadStart(StartDownload));
                t.Start(firstNotCompleted);
            }
        }

        public void SaveAllTasks()
        {
            try
            {
                string body = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\r\n<Downloads>\r\n";
                foreach (DownloadTask d in dt) body += d.ToXML(2);
                body += "</Downloads>";
                File.WriteAllText(Settings.SettingSavePath + "\\Config\\Downloads.xml", body);
            }
            catch { }
        }

        private void StartDownload(object Index)
        {
            int index = (int)Index;
            if (dt[index].IsLyrics)
            {
                SongStreaming ss = new SongStreaming(dt[index].Song.Id);
                ss.GetSongStreamingData();
                dwr.Url = ss.LyricsUrl;
            }
            else dwr.Url = dt[index].Song.GetDownloadUrl();
            dwr.FileName = dt[index].FileName;
            dwr.Start();

            while (!dwr.IsDownloadStarted) { }
            dt[index].IsDownloading = true;
            dt[index].IsCompleted = false;
            SetState(index, 0);
            SetTimerEnable();
        }

        private void SetTimerEnable()
        {
            if (this.InvokeRequired)
                this.Invoke(new SetTimerEnableCallBack(SetTimerEnable));
            else timer1.Enabled = true;
        }

        private void SetState(int index, int state)
        {
            if (index >= dt.Count || index >= dgw.Rows.Count) return;
            DataGridViewImageCell ic = (DataGridViewImageCell)dgw.Rows[index].Cells[0];
            switch (state)
            {
                case 0:
                    ic.Value = res.start;
                    break;
                case 1:
                    ic.Value = res.pause;
                    break;
                case 2:
                    ic.Value = res.link;
                    break;
                case 3:
                    ic.Value = res.exclamation;
                    break;
                case 4:
                    ic.Value = res.done;
                    break;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            int i = GetDownloadingIndex();
            //if (dwr.IsDownloadCompleted)
            //{
            //    dwr_DownloadCompleted(dwr, EventArgs.Empty);
            //    return;
            //}
            if (i == -1) return;

            int speed = (int)(dwr.DownloadedSize - oldDownloadedSize);
            int rTime = speed == 0 ? 0 : (dwr.FileLenght - dwr.DownloadedSize) / speed;
            dgw.Rows[i].Cells[3].Value = PaintProgressBar(dwr.DownloadedSize / (double)dwr.FileLenght, dgw.Columns[3].Width);
            dgw.Rows[i].Cells[4].Value = Helper.GetStringFromBytes(speed) + "/s";
            dgw.Rows[i].Cells[5].Value = rTime < 0 ? "未知" : (new DateTime(TimeSpan.FromSeconds(rTime).Ticks)).ToString("HH:mm:ss");
            oldDownloadedSize = dwr.DownloadedSize;
        } 

        private void frmDownloader_Load(object sender, EventArgs e)
        {
            //RefreshTask();
        }

        private void frmDownloader_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            this.Hide();
        }

        private void dgw_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && e.RowIndex >= 0 && !dgw.Rows[e.RowIndex].Selected)
            {
                dgw.ClearSelection();
                dgw.Rows[e.RowIndex].Selected = true;
            }
        }

        private void mnuStartPause_Click(object sender, EventArgs e)
        {
            if (dgw.SelectedRows.Count == 0) return;
            int i = GetDownloadingIndex();
            if (i == -1)
            {
                oldDownloadedSize = 0;
                Thread t = new Thread(new ParameterizedThreadStart(StartDownload));
                t.Start(dgw.SelectedRows[0].Index);
            }
            else
            {
                if (dgw.SelectedRows[0].Index != i) return;
                if (dwr.IsDownloadStarted)
                {
                    dwr.Stop();
                    SetState(i, 1);
                }
                else
                {
                    dwr.Start();
                    SetState(i, 0);
                }
            }
        }

        private void mnuRestartDownload_Click(object sender, EventArgs e)
        {
            if (dgw.SelectedRows.Count == 0) return;
            int i = GetDownloadingIndex();

            for (int j = 0; j < dgw.SelectedRows.Count; j++)
            {
                int k = dgw.SelectedRows[j].Index;
                if (i == k)
                {
                    while (dwr.FileLenght == 0) { }
                    oldDownloadedSize = 0;
                    dwr.Start(0, dwr.FileLenght);
                    SetState(i, 0);
                }
                else
                {
                    try
                    {
                        if (File.Exists(dt[k].FileName + ".cfg"))
                            File.Delete(dt[k].FileName + ".cfg");
                        if (File.Exists(dt[k].FileName))
                            File.Delete(dt[k].FileName);
                    }
                    catch { }
                    dgw.Rows[j].Cells[3].Value = PaintProgressBar(0, dgw.Columns[3].Width);

                    if (i == -1)
                    {
                        oldDownloadedSize = 0;
                        Thread t = new Thread(new ParameterizedThreadStart(StartDownload));
                        t.Start(k);
                    }
                }
            }

            SaveAllTasks();
        }

        private void mnuDelete_Click(object sender, EventArgs e)
        {
            if (dgw.SelectedRows.Count == 0) return;
            int i = GetDownloadingIndex();

            int[] index = new int[dgw.SelectedRows.Count];
            for (int j = 0; j < dgw.SelectedRows.Count; j++)
                index[j] = dgw.SelectedRows[j].Index;

            for (int j = 0; j < index.Length; j++)
            {
                if (i == index[j]) dwr.Stop();
                dgw.Rows.RemoveAt(index[j]);
                dt.RemoveAt(index[j]);
            }
            RefreshTask();
            SaveAllTasks();
        }

        private void menuItem2_Click(object sender, EventArgs e)
        {
            if (dgw.SelectedRows.Count == 0) return;
            int i = dgw.SelectedRows[0].Index;
            if (dt[i].IsCompleted)
                System.Diagnostics.Process.Start(dt[i].FileName);
        }

        private void menuItem3_Click(object sender, EventArgs e)
        {
            if (dgw.SelectedRows.Count == 0) return;
            int i = dgw.SelectedRows[0].Index;
            System.Diagnostics.Process.Start(Path.GetDirectoryName(dt[i].FileName));
        }

        private void dgw_SelectionChanged(object sender, EventArgs e)
        {
            btnDelete.Enabled = dgw.SelectedRows.Count != 0;
            btnOpen.Enabled = dgw.SelectedRows.Count != 0;
            btnOpenFolder.Enabled = dgw.SelectedRows.Count != 0;
            btnReStart.Enabled = dgw.SelectedRows.Count != 0;
            btnStartPause.Enabled = dgw.SelectedRows.Count != 0 && !dt[dgw.SelectedRows[0].Index].IsCompleted;
        }
    }

    public class DataGridViewX : DataGridView
    {
        public DataGridViewX()
        {
            this.DoubleBuffered = true;
        }
    }
}
